﻿#include "PluginFluent.h"
#include "mainWindow/mainWindow.h"
#include <QString>
#include "ModelData/modelDataFactory.h"
#include "ModelData/modelDataSingleton.h"
#include "ModelData/modelDataBase.h"
#include "MainWidgets/ProjectTreeFactory.h"
#include "IO/IOConfig.h"
#include "IO/TemplateReplacer.h"
#include "meshData/meshSingleton.h"
#include "meshData/meshSet.h"
#include "meshData/meshKernal.h"
#include "BCBase/BCBase.h"
#include "ConfigOptions/ConfigOptions.h"
#include "ConfigOptions/SolverInfo.h"
#include <QDebug>
#include <QFile>
#include <QApplication>
#include <QDir>

void Register(GUI::MainWindow* m, QList<Plugins::PluginBase*>* ps)
{
    Plugins::PluginBase* p = new Plugins::PluginFluent(m);
    ps->append(p);
}
namespace Plugins
{
    PluginFluent::PluginFluent(GUI::MainWindow* m)
    {
        _mainwindow = m;
        _describe = "Fluent Function Plugin";
    }
    PluginFluent::~PluginFluent()
    {
    }
    bool PluginFluent::install()
    {
        IO::IOConfigure::RegisterInputFile("Fluent", BeforeCalcFunc);
        return true;
    }
    bool PluginFluent::uninstall()
    {
        IO::IOConfigure::RemoveInputFile("Fluent");
        return true;
    }
}
QString BCType2QString(BCBase::BCType type)
{
    if (type == BCBase::Inlet)
        return "velocity-inlet";
    else if (type == BCBase::Outlet)
        return "outflow";
    else if (type == BCBase::Wall)
        return "wall";
}
struct BCExchange
{
    QString bcName;
    BCBase::BCType toType;
};
bool ReplaceMeshFileBCType(const QString & fileName, QVector<BCExchange> exchangInfos)
{
    QFile file(fileName);
    if (!file.exists()) { return false; }
    QString head = QString("(45 (");
    QString tail = QString(")())\r\n");
    if (file.open(QIODevice::ReadWrite))
    {
        file.seek(file.size() - 1000);
        QString toContent;
        while (!file.atEnd())
        {
            QString lineContent = file.readLine();
            if (lineContent.size() < 6)
            {
                toContent += lineContent;
                continue;
            }
            if (lineContent.left(head.size()) == head && lineContent.right(tail.size()) == tail)
            {
                QStringList infos = lineContent.mid(5, lineContent.size() - 5 - 6).split(" ", QString::SkipEmptyParts);
                if (infos.size() == 3)
                {
                    QString id = infos[0], type = infos[1], name = infos[2];
                    bool needReplace = false;
                    for (BCExchange one : exchangInfos)
                    {
                        if (name == one.bcName)
                        {
                            QString setName = "(45 (" + id + " " + BCType2QString(one.toType) + " " + name + ")())\r\n";
                            toContent += setName;
                            needReplace = true;
                        }
                    }
                    if (!needReplace)
                        toContent += lineContent;
                }
            }
            else
                toContent += lineContent;
        }
        file.seek(0);
        QString totalContent = file.read(file.size() - 1000) + toContent;
        file.seek(0);
        file.resize(totalContent.size());
        file.write(totalContent.toStdString().c_str());
        return true;
    }
    else
        return false;
}
bool BCOperation(ModelData::ModelDataBase* d, QString & meshFilePath)
{
    int nBC = d->getBCCount();
    if (nBC == 0) { return false; }
    QMap<QString, QVector<BCExchange>> bcExchangeInfos;
    for (int iBC = 0; iBC < nBC; ++iBC)
    {
        BCBase::BCBase * pBC = d->getBCAt(iBC);
        if (!pBC) { continue; }
        ///<MG 获取边界条件类型，及对应边界条件网格组件的名称
        BCBase::BCType bcType = pBC->getBCType();
        int meshSetID = pBC->getComponentID();
        MeshData::MeshSet * meshSet = MeshData::MeshData::getInstance()->getMeshSetByID(meshSetID);
        if (!meshSet) { continue; }
        QString meshSetName = meshSet->getName();
        QList<int> meshKernalIDs = meshSet->getKernals();
        for (int KernalID : meshKernalIDs)
        {
            MeshData::MeshKernal * pKernal = MeshData::MeshData::getInstance()->getKernalByID(KernalID);
            if (!pKernal) { continue; }
            QString filePath = pKernal->getPath();
            ///<MG 判定类型，如果是mesh将原有名字为 meshSetName 的单元 改成bcType 类型单元
            if (filePath.contains(".msh"))
            {
                BCExchange one;
                one.bcName = meshSetName;
                one.toType = bcType;
                if (bcExchangeInfos.contains(filePath))
                {
                    bcExchangeInfos[filePath].push_back(one);
                }
                else
                {
                    QVector<BCExchange> exchanges;
                    exchanges.push_back(one);
                    bcExchangeInfos.insert(filePath, exchanges);
                }
            }
        }
    }
    ///<MG 进行替换
    for (QString filePath : bcExchangeInfos.keys())
        if (!ReplaceMeshFileBCType(filePath, bcExchangeInfos[filePath])) { return false; }
    if (bcExchangeInfos.size() == 1)
        meshFilePath = bcExchangeInfos.keys()[0];
    return true;
}
bool JournalOperation(QString path, ModelData::ModelDataBase* d, QString meshFilePah)
{
    QString templatePath = QApplication::applicationDirPath() + "/../Template/template.jou";
    QFile file(templatePath);
    QString toPath = path + "/script.jou";
    if (file.exists(toPath)) { file.remove(toPath); }
    QString toOutputPath = path + "/Result/Result.cgns";
    file.copy(templatePath, toPath);
    ///<MG 向数据中添加参数
    DataProperty::ParameterBase * paraMshPath = d->getParameterByName("MshPath");
    if (!paraMshPath)
    {
        paraMshPath = d->appendParameter(DataProperty::Para_String);
        paraMshPath->setDescribe("MshPath");
    }
    paraMshPath->setValueFromString(meshFilePah);
    DataProperty::ParameterBase * paraOutputPath = d->getParameterByName("OutputPath");
    if (!paraOutputPath)
    {
        paraOutputPath = d->appendParameter(DataProperty::Para_String);
        paraOutputPath->setDescribe("OutputPath");
    }
    paraOutputPath->setValueFromString(toOutputPath);
    ///<MG 对脚本中的值进行替换
    IO::TempalteReplacer replcer(d);
    replcer.appendFile(toPath);
    replcer.replace();
    ///<MG 删除添加的参数
    d->removeParameter(paraMshPath);
    d->removeParameter(paraOutputPath);
    ///<MG 为结果文件创建文件夹
    QDir dir;
    dir.mkdir(path + "/Result");
    return true;
}
bool PLUGINFLUENTAPI BeforeCalcFunc(QString path, ModelData::ModelDataBase* d)
{
    ///<MG Step1 获取当前项目中选中设置边界条件的MeshSet与那些MeshKernal相关，按照设置改写文件中的边界信息
    QString meshFilePath;
    if (!BCOperation(d, meshFilePath)) { return false; }
    if (meshFilePath.isEmpty()) { return false; }
    ///<MG STEP 2 对journal脚本进行操作
    if (!JournalOperation(path, d, meshFilePath)) { return false; }
    return true;
}
